﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HM.UI.HMService;
using System.ComponentModel;
using System.Windows.Input;
using GalaSoft.MvvmLight.Command;
using System.Windows;
using HM.UI.Windows;
using HM.UI.Windows.Management;
using HM.UI.Converters;
using GalaSoft.MvvmLight;

namespace HM.UI
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        private HMServiceClient proxy = new HMServiceClient();

        public MainWindowViewModel()
        {
            // "Home" tab RelayCommands:

            AddPayment = new RelayCommand(AddPaymentExecute, CanExecuteAddPayment);
            AddExpense = new RelayCommand(AddExpenseExecute, CanExecuteAddExpense);


            // "Reports tab" RelayCommands:

            OpenAllPaymentsReportWindow = new RelayCommand(OpenAllPaymentsWindowExecute);
            OpenPaymentsByTenantIdReportWindow = new RelayCommand(OpenPaymentsByTenantIdReportWindowExecute, CanExecuteOpenPaymentsByTenantIdReportWindow);
            OpenPaymentsByDateRangeReportWindow = new RelayCommand(OpenPaymentsByDateRangeReportWindowExecute, CanExecuteOpenPaymentsByDateRangeReportWindow);
            OpenAllExpensesReportWindow = new RelayCommand(OpenAllExpensesWindowExecute);
            OpenExpensesByDateRangeReportWindow = new RelayCommand(OpenExpensesByDateRangeReportWindowExecute, CanExecuteOpenExpensesByDateRangeReportWindow);


            // "Management" tab RelayCommands:

            OpenManageExpensesWindow = new RelayCommand(OpenManageExpensesWindowExecute);
            OpenManagePaymentsWindow = new RelayCommand(OpenManagePaymentsWindowExecute);
            OpenManageRegularExpensesWindow = new RelayCommand(OpenManageRegularExpensesWindowExecute);
            OpenManageTenantsWindow = new RelayCommand(OpenManageTenantsWindowExecute);

            this.RefreshTenants(); // fills list of tenants in combobox
            this.RefreshRegularExpenses(); // fills list of regular expenses in combobox
            this.RefreshCash(); // displays updated cash amount (both for current month and actual cash)
        }

        #region Home Tab

        #region Properties

        #region Cash
        private string cash;
        public string Cash
        {
            get
            {
                return "Overall Balance: " + this.cash;
            }

            set
            {
                if (cash != value)
                {
                    this.cash = value;
                    this.OnPropertyChanged("Cash");
                }
            }
        }

        private string cashThisMonth;
        public string CashThisMonth
        {
            get
            {
                return "Balance This Month: " + this.cashThisMonth;
            }

            set
            {
                if (cashThisMonth != value)
                {
                    this.cashThisMonth = value;
                    this.OnPropertyChanged("CashThisMonth");
                }
            }
        }
        #endregion

        #region Expense

        private Expense expense;
        public Expense Expense
        {
            get
            {
                return this.expense;
            }

            set
            {
                if (expense != value)
                {
                    this.expense = value;
                    this.OnPropertyChanged("Expense");
                }
            }
        }

        private string expenseDescription;
        public string ExpenseDescription
        {
            get { return expenseDescription; }
            set
            {
                if (expenseDescription != value)
                {
                    expenseDescription = value;
                    OnPropertyChanged("ExpenseDescription");
                }
            }
        }

        private Decimal? expenseAmount;
        public Decimal? ExpenseAmount
        {
            get { return expenseAmount; }
            set
            {
                if (expenseAmount != value)
                {
                    expenseAmount = value;
                    OnPropertyChanged("ExpenseAmount");
                }
            }
        }

        #endregion

        #region Payment

        private Payment payment;

        public Payment Payment
        {
            get
            {
                return this.payment;
            }

            set
            {
                if (payment != value)
                {
                    this.payment = value;
                    this.OnPropertyChanged("Payment");
                }
            }
        }

        private Decimal? paymentAmount;
        public Decimal? PaymentAmount
        {
            get { return paymentAmount; }
            set
            {
                if (paymentAmount != value)
                {
                    paymentAmount = value;
                    OnPropertyChanged("PaymentAmount");
                }
            }
        }

        private DateTime? paymentDate;
        public DateTime? PaymentDate
        {
            get { return paymentDate; }
            set
            {
                if (paymentDate != value)
                {
                    paymentDate = value;
                    OnPropertyChanged("PaymentDate");
                }
            }
        }

        private IEnumerable<Tenant> tenants;
        public IEnumerable<Tenant> Tenants
        {
            get
            {
                return this.tenants;
            }

            set
            {
                if (tenants != value)
                {
                    this.tenants = value;
                    this.OnPropertyChanged("Tenants");
                }
            }
        }

        private Tenant selectedTenant;
        public Tenant SelectedTenant
        {
            get
            {
                return selectedTenant;
            }

            set
            {
                if (selectedTenant != value)
                {
                    this.selectedTenant = value;
                    this.OnPropertyChanged("SelectedTenant");
                }
            }
        }

        #endregion

        #region RegularExpense
        private RegularExpense regularExpense;
        public RegularExpense RegularExpense
        {
            get
            {
                return this.regularExpense;
            }

            set
            {
                if (regularExpense != value)
                {
                    this.regularExpense = value;
                    this.OnPropertyChanged("RegularExpense");
                }
            }
        }

        private string regularExpenseDescription;
        public string RegularExpenseDescription
        {
            get { return regularExpenseDescription; }
            set
            {
                if (regularExpenseDescription != value)
                {
                    regularExpenseDescription = value;
                    OnPropertyChanged("RegularExpenseDescription");
                }
            }
        }

        private IEnumerable<RegularExpense> regularExpenses;
        public IEnumerable<RegularExpense> RegularExpenses
        {
            get
            {
                return this.regularExpenses;
            }

            set
            {
                if (regularExpenses != value)
                {
                    this.regularExpenses = value;
                    this.OnPropertyChanged("RegularExpenses");
                }
            }
        }

        private RegularExpense selectedRegularExpense;
        public RegularExpense SelectedRegularExpense
        {
            get
            {
                return selectedRegularExpense;
            }

            set
            {
                if (selectedRegularExpense != value)
                {
                    this.selectedRegularExpense = value;
                    this.OnPropertyChanged("SelectedRegularExpense");
                }
            }
        }
        #endregion

        #endregion

        #region RelayCommands

        public RelayCommand AddPayment { get; set; }
        public RelayCommand AddExpense { get; set; }

        #endregion

        #region Execute
        private void AddPaymentExecute()
        {
            this.proxy.AddPaymentCompleted += (s, e) =>
            {
                this.PaymentAmount = null;
                this.PaymentDate = null;
                this.SelectedTenant = null;
                RefreshCash();
            };

            proxy.AddPaymentAsync(new Payment()
            {
                UpdateDate = DateTime.Now,
                Amount = this.PaymentAmount,
                PaymentDate = this.PaymentDate,
                TenantId = this.SelectedTenant.Id
            });
        }

        private void AddExpenseExecute()
        {
            this.proxy.AddExpenseCompleted += (s, e) =>
            {
                this.ExpenseAmount = null;
                this.ExpenseDescription = "";
                this.SelectedRegularExpense = null;
                RefreshCash();
            };

            if (SelectedRegularExpense != null)
            {
                this.ExpenseDescription = this.SelectedRegularExpense.Description;
            }

            proxy.AddExpenseAsync(new Expense()
            {
                PaymentDate = DateTime.Now,
                Amount = this.ExpenseAmount,
                Description = this.ExpenseDescription
            });
        }

        #endregion

        #region CanExecute
        private bool CanExecuteAddPayment()
        {
            // The user can add a new Paymet only when the Payment's Amount is inserted in the TextBox,
            // the PaymentDate is selected from the DatePicker
            // and the payer (Tenant) is selected from the ComboBox.
            return
                (
                    this.PaymentAmount != null &&
                    this.PaymentDate != null &&
                    this.SelectedTenant != null
                );
        }

        private bool CanExecuteAddExpense()
        {
            // The user can add a new Expense only when the Expense's Amount is inserted in the TextBox,
            // and the Descriptoin is inserted in the TextBox (or selected from ComboBox).
            return
                (
                    this.ExpenseAmount != null &&
                    (
                        !string.IsNullOrWhiteSpace(this.ExpenseDescription) ||
                        this.SelectedRegularExpense != null
                    )
                );
        }
        #endregion

        #region Refresh
        private void RefreshCash()
        {
            this.proxy.GetCashCompleted += (s, e) =>
            {
                this.Cash = (e.Result).ToString();
            };
            this.proxy.GetCashAsync();
            RefreshCashThisMonth();
        }

        private void RefreshCashThisMonth()
        {
            this.proxy.GetCashForThisMonthCompleted += (s, e) =>
            {
                this.CashThisMonth = (e.Result).ToString();
            };
            this.proxy.GetCashForThisMonthAsync();
        }

        private void RefreshTenants()
        {
            this.proxy.GetTenantsCompleted += (s, e) =>
            {
                this.Tenants = e.Result;
            };
            this.proxy.GetTenantsAsync();
        }

        private void RefreshRegularExpenses()
        {
            this.proxy.GetRegularExpensesCompleted += (s, e) =>
            {
                this.RegularExpenses = e.Result;
            };
            this.proxy.GetRegularExpensesAsync();
        }
        #endregion

        #endregion

        #region Reports Tab

        #region Properties

        #region For Payments

        private Tenant selectedTenantForReport;
        public Tenant SelectedTenantForReport
        {
            get
            {
                return selectedTenantForReport;
            }

            set
            {
                if (selectedTenantForReport != value)
                {
                    this.selectedTenantForReport = value;
                    this.OnPropertyChanged("SelectedTenantForReport");
                }
            }
        }

        private DateTime? selectedFromDateForPaymentsReport;
        public DateTime? SelectedFromDateForPaymentsReport
        {
            get
            {
                return selectedFromDateForPaymentsReport;
            }

            set
            {
                if (selectedFromDateForPaymentsReport != value)
                {
                    this.selectedFromDateForPaymentsReport = value;
                    this.OnPropertyChanged("SelectedFromDateForPaymentsReport");
                }
            }
        }

        private DateTime? selectedToDateForPaymentsReport;
        public DateTime? SelectedToDateForPaymentsReport
        {
            get
            {
                return selectedToDateForPaymentsReport;
            }

            set
            {
                if (selectedToDateForPaymentsReport != value)
                {
                    this.selectedToDateForPaymentsReport = value;
                    this.OnPropertyChanged("SelectedToDateForPaymentsReport");
                }
            }
        }
        #endregion

        #region For Expenses

        private DateTime? selectedFromDateForExpensesReport;
        public DateTime? SelectedFromDateForExpensesReport
        {
            get
            {
                return selectedFromDateForExpensesReport;
            }

            set
            {
                if (selectedFromDateForExpensesReport != value)
                {
                    this.selectedFromDateForExpensesReport = value;
                    this.OnPropertyChanged("SelectedFromDateForExpensesReport");
                }
            }
        }

        private DateTime? selectedToDateForExpensesReport;
        public DateTime? SelectedToDateForExpensesReport
        {
            get
            {
                return selectedToDateForExpensesReport;
            }

            set
            {
                if (selectedToDateForExpensesReport != value)
                {
                    this.selectedToDateForExpensesReport = value;
                    this.OnPropertyChanged("SelectedToDateForExpensesReport");
                }
            }
        }

        #endregion

        #endregion

        #region RelayCommands

        public RelayCommand OpenAllPaymentsReportWindow { get; private set; }
        public RelayCommand OpenPaymentsByTenantIdReportWindow { get; private set; }
        public RelayCommand OpenPaymentsByDateRangeReportWindow { get; private set; }
        public RelayCommand OpenAllExpensesReportWindow { get; private set; }
        public RelayCommand OpenExpensesByDateRangeReportWindow { get; private set; }

        #endregion

        #region Execute

        private void OpenAllPaymentsWindowExecute()
        {
            var paymentsReportWindow = new PaymentsReportWindow();
            paymentsReportWindow.Show();

            paymentsReportWindow.DataContext = new PaymentsReportViewModel();
        }

        private void OpenPaymentsByTenantIdReportWindowExecute()
        {
            var paymentsReportWindow = new PaymentsReportWindow();
            paymentsReportWindow.Show();

            paymentsReportWindow.DataContext = new PaymentsReportViewModel(SelectedTenantForReport);
        }

        private void OpenPaymentsByDateRangeReportWindowExecute()
        {
            var paymentsReportWindow = new PaymentsReportWindow();
            paymentsReportWindow.Show();

            paymentsReportWindow.DataContext = new PaymentsReportViewModel
            (
                SelectedFromDateForPaymentsReport,
                SelectedToDateForPaymentsReport
            );
        }

        private void OpenAllExpensesWindowExecute()
        {
            var expensesReportWindow = new ExpensesReportWindow();
            expensesReportWindow.Show();

            expensesReportWindow.DataContext = new ExpensesReportViewModel();
        }

        private void OpenExpensesByDateRangeReportWindowExecute()
        {
            var expensesReportWindow = new ExpensesReportWindow();
            expensesReportWindow.Show();

            expensesReportWindow.DataContext = new ExpensesReportViewModel
            (
                SelectedFromDateForExpensesReport,
                SelectedToDateForExpensesReport
            );
        }

        #endregion

        #region CanExecute
        private bool CanExecuteOpenPaymentsByTenantIdReportWindow()
        {
            return
                (
                    this.SelectedTenantForReport != null
                );
        }

        private bool CanExecuteOpenPaymentsByDateRangeReportWindow()
        {
            return
                (
                    selectedFromDateForPaymentsReport != null &&
                    SelectedToDateForPaymentsReport != null
                );
        }

        private bool CanExecuteOpenExpensesByDateRangeReportWindow()
        {
            return
                (
                    SelectedFromDateForExpensesReport != null &&
                    SelectedToDateForExpensesReport != null
                );
        }
        #endregion

        #endregion

        #region Management Tab

        #region RelayCommands

        public RelayCommand OpenManageExpensesWindow { get; private set; }
        public RelayCommand OpenManagePaymentsWindow { get; private set; }
        public RelayCommand OpenManageRegularExpensesWindow { get; private set; }
        public RelayCommand OpenManageTenantsWindow { get; private set; }

        #endregion

        #region Execute

        private void OpenManageExpensesWindowExecute()
        {
            var manageExpensesWindow = new ManageExpensesWindow();
            manageExpensesWindow.Closed += new EventHandler(ManageExpensesWindow_Closed);
            manageExpensesWindow.Show();
        }

        private void OpenManagePaymentsWindowExecute()
        {
            var managePaymentsWindow = new ManagePaymentsWindow();
            managePaymentsWindow.Closed += new EventHandler(ManagePaymentsWindow_Closed);
            managePaymentsWindow.Show();
        }

        private void OpenManageRegularExpensesWindowExecute()
        {
            var manageRegularExpensesWindow = new ManageRegularExpensesWindow();
            manageRegularExpensesWindow.Closed += new EventHandler(ManageRegularExpensesWindow_Closed);
            manageRegularExpensesWindow.Show();
        }

        private void OpenManageTenantsWindowExecute()
        {
            var manageTenantsWindow = new ManageTenantsWindow();
            manageTenantsWindow.Closed += new EventHandler(ManageTenantsWindow_Closed);
            manageTenantsWindow.Show();
        }
        #endregion

        #region Events

        void ManageExpensesWindow_Closed(object sender, EventArgs e)
        {
            this.RefreshCash();
            ((ManageExpensesWindow)sender).Closed -= ManageExpensesWindow_Closed;
        }

        void ManagePaymentsWindow_Closed(object sender, EventArgs e)
        {
            this.RefreshCash();
            ((ManagePaymentsWindow)sender).Closed -= ManagePaymentsWindow_Closed;
        }

        void ManageRegularExpensesWindow_Closed(object sender, EventArgs e)
        {
            this.RefreshRegularExpenses();
            ((ManageRegularExpensesWindow)sender).Closed -= ManageRegularExpensesWindow_Closed;
        }

        void ManageTenantsWindow_Closed(object sender, EventArgs e)
        {
            this.RefreshTenants();
            ((ManageTenantsWindow)sender).Closed -= ManageTenantsWindow_Closed;
        }
        #endregion

        #endregion


        private void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}
